<template>
  <div class="mains">
    <canvas class="mycanvas" ref="mycanvas" :width="canvasWidth" :height="canvasHeight" @mousedown="canvasDown($event)"
      @mousemove="canvasMove($event)" @mouseup="canvasUp($event)">浏览器不持之canvas</canvas>
  </div>
</template>

<script setup>
import { ref, reactive, watch, onMounted } from 'vue';
// 响应式数据
const isdraw = ref(false);
const ctx = ref(null);
const coordinates = ref([]);
const cor_index = ref(0);
const endtip = ref(false);
const all_coordinates = ref([]);
const isdrag = ref(false);
const drag_index = ref([-1, -1]);
const img = ref('');
const val = reactive({ cor_x: '', cor_y: '' });
const upVal = reactive({ cor_x: '', cor_y: '' });
const isShowBox = ref(false);

// 监听props
watch(() => props.showBox, (a) => {
  isShowBox.value = a;
  initDraw();
});

onMounted(()=>{
  initDraw()
})

const props = defineProps({
  coordinatesData: {
      type: Array, //需要展示的坐标
    },
    showBox: {
      type: Boolean, //是否显示圆圈
    },
    canvasWidth: {
      type: Number, //画布宽度
      default:800,
    },
    canvasHeight: {
      type: Number, //画布高度
      default:800,
    },
})

// 清空方法
const test = () => {
  all_coordinates.value = [];
  coordinates.value = [];
  isdraw.value = false;
  endtip.value = false;
  ctx.value.clearRect(0, 0, props.canvasWidth, props.canvasHeight);
}

// 填充方法
const fillarea = () => {
  ctx.value.fillStyle = 'rgba(255, 77, 79,0.1)';
  for (let i = 0; i < all_coordinates.value.length; i++) {
    let cors = all_coordinates.value[i];
    let x0 = cors[0].cor_x;
    let y0 = cors[0].cor_y;
    ctx.value.beginPath();
    ctx.value.moveTo(x0, y0);
    for (let j = 1; j < cors.length; j++) {
      let x = cors[j].cor_x;
      let y = cors[j].cor_y;
      ctx.value.lineTo(x, y);
    }
    ctx.value.fill();
    ctx.value.closePath();
  }
}

// 判断是否交叉方法
const move = (val) => {
  let flag1 = false;
  let flag2 = false;
  if (all_coordinates.value[0]) {
    let ind = isdragpoint(val.cor_x, val.cor_y);
    let arr = [...all_coordinates.value[0]];
    arr.push(arr[0]);
    if (ind != -1) {
      arr[ind] = val;
      arr.some((item, index) => {
        if (index < arr.length - 1) {
          arr.some((v, i) => {
            if (i < arr.length - 1) {
              if (
                isIntersect(
                  {
                    x1: item.cor_x,
                    y1: item.cor_y,
                    x2: arr[index + 1].cor_x,
                    y2: arr[index + 1].cor_y,
                  },
                  {
                    x1: v.cor_x,
                    y1: v.cor_y,
                    x2: arr[i + 1].cor_x,
                    y2: arr[i + 1].cor_y,
                  },
                )
              ) {
                flag2 = true;
              }
            }
          });
        }
      });
    }
  } else {
    flag1 = coordinates.value.some((v, i) => {
      if (i < coordinates.value.length - 2) {
        return isIntersect(
          { x1: v.cor_x, y1: v.cor_y, x2: coordinates.value[i + 1].cor_x, y2: coordinates.value[i + 1].cor_y },
          {
            x1: coordinates.value[coordinates.value.length - 1].cor_x,
            y1: coordinates.value[coordinates.value.length - 1].cor_y,
            x2: val.cor_x,
            y2: val.cor_y,
          },
        );
      }
    });
  }

  if (flag1 == false && flag2 == false) {
    return false;
  } else {
    message.warning('线段不能交叉');
    return true;
  }
}

// 初始化画布对象
const initDraw = () => {
  const canvas = document.querySelector('.mycanvas');
  ctx.value = canvas.getContext('2d');
  ctx.value.strokeStyle = 'rgb(235, 57, 65)';
  console.log(147, coordinates.value);
  if (coordinates.value.length > 0) {
    all_coordinates.value = [];
    coordinates.value.forEach(e => {
      all_coordinates.value.push({
        cor_x: Math.round((props.canvasWidth * e[0]) / 100),
        cor_y: Math.round((props.canvasHeight * e[1]) / 100),
      });
    });
    console.log(189, coordinates.value);
    drawClosePath();
  }
}

//判断是否是同一个点
const isdragpoint = (x, y) => {
  if (all_coordinates.value.length === 0) {
    return false;
  }
  for (let i = 0; i < all_coordinates.value.length; i++) {
    for (let j = 0; j < all_coordinates.value[i].length; j++) {
      const px = all_coordinates.value[i][j].cor_x;
      const py = all_coordinates.value[i][j].cor_y;
      if (Math.abs(x - px) <= 8 && Math.abs(y - py) <= 8) {
        drag_index.value[0] = i;
        drag_index.value[1] = j;
        return j;
      }
    }
  }
  return false;
}

//手动闭合路径
const handleClosePath = () => {
  const arr = [coordinates.value];
  for (let i = 0; i < arr.length; i++) {
    for (let j = 0; j < arr[i].length; j++) {
      const px = arr[i][j].cor_x;
      const py = arr[i][j].cor_y;
      if (Math.abs(x - px) <= 8 && Math.abs(y - py) <= 8) {
        console.log(isdraw.value, j === 0);
        if (isdraw.value && j === 0 && !move(upVal)) {
          drawClosePath();
          return true;
        }
      }
    }
  }
  return false;
}

//鼠标按下
const canvasDown = (e) => {
  // if (!isShowBox.value) return;
  console.log('鼠标点击');

  const x = e.offsetX;
  const y = e.offsetY;
  val.cor_x = x;
  val.cor_y = y;

  if (handleClosePath(x, y)) return;
  console.log(267, val);
  isdragpoint(x, y);
  if (move(val)) return;
  if (isdragpoint(x, y) === 0 || isdragpoint(x, y)) {
    isdrag.value = true;
    return 0;
  }

  // 画布中鼠标按下
  if (endtip.value) {
    // 已经结束了上个多边形的绘制，把上个多边形的坐标放入数组，同时清空单个多边形数组信息
    endtip.value = false;
  }
  // 获取鼠标按下的坐标，放入数组中
  if (all_coordinates.value.length === 1) {
    return;
  }
  coordinates.value.push({ cor_x: x, cor_y: y });
  isdraw.value = true; //正在画多边形
}

//把所有多边形画出来
const drawLines = () => {
  for (let i = 0; i < all_coordinates.value.length; i++) {
    const cors = all_coordinates.value[i];
    //前后坐标连线
    for (let j = 0; j < cors.length - 1; j++) {
      ctx.value.beginPath();
      const x0 = cors[j].cor_x;
      const y0 = cors[j].cor_y;
      const x1 = cors[j + 1].cor_x;
      const y1 = cors[j + 1].cor_y;
      ctx.value.moveTo(x0, y0);
      ctx.value.lineTo(x1, y1);
      ctx.value.stroke();
      ctx.value.closePath();
    }
    //最后一个与第一个连线
    const begin_x = cors[0].cor_x;
    const begin_y = cors[0].cor_y;
    const end_x = cors[cors.length - 1].cor_x;
    const end_y = cors[cors.length - 1].cor_y;
    ctx.value.beginPath();
    ctx.value.moveTo(begin_x, begin_y);
    ctx.value.lineTo(end_x, end_y);
    ctx.value.stroke();
    ctx.value.closePath();
  }
}


const drawLine = ()=>{
   // 把当前绘制的多边形之前的坐标线段绘制出来
   for (let i = 0; i < coordinates.value.length - 1; i++) {
    ctx.value.beginPath();
    const x0 = coordinates.value[i].cor_x;
    const y0 = coordinates.value[i].cor_y;
    const x1 = coordinates.value[i + 1].cor_x;
    const y1 = coordinates.value[i + 1].cor_y;
    ctx.value.moveTo(x0, y0);
    ctx.value.lineTo(x1, y1);
    ctx.value.stroke();
    ctx.value.closePath();
  }
}

const drawCircle = ()=>{
  ctx.value.strokeStyle = 'rgb(235, 57, 65)';
  ctx.value.fillStyle = '#fff';
  for (let i = 0; i < coordinates.value.length; i++) {
    const x = coordinates.value[i].cor_x;
    const y = coordinates.value[i].cor_y;
    ctx.value.beginPath();
    ctx.value.moveTo(x, y);
    ctx.value.arc(x, y, 8, 0, Math.PI * 2);
    ctx.value.stroke();
    ctx.value.fill();
    ctx.value.closePath();
  }
}


const drawCircles = () => {
  ctx.value.strokeStyle = 'rgb(235, 57, 65)';
  ctx.value.fillStyle = '#fff';
  for (let i = 0; i < all_coordinates.value.length; i++) {
    const cors = all_coordinates.value[i];
    for (let j = 0; j < cors.length; j++) {
      const x = cors[j].cor_x;
      const y = cors[j].cor_y;
      ctx.value.beginPath();
      ctx.value.moveTo(x, y);
      ctx.value.arc(x, y, 8, 0, Math.PI * 2);
      ctx.value.stroke();
      ctx.value.fill();
      ctx.value.closePath();
    }
  }
}


const canvasUp = (e) => {
  if (!isShowBox.value) return;
  drag_index.value = [-1, -1];
  if (isdrag.value) {
    if (all_coordinates.value.length) {
      upVal.cor_x = e.offsetX;
      upVal.cor_y = e.offsetY;
      if (move(upVal)) {
        console.log(273);
        canvasMove({ offsetX: val.cor_x, offsetY: val.cor_y });
        isdrag.value = false;
        return;
      }
    }
    isdrag.value = false;
  }
}

// 辅助函数 检查两个线是否交叉
const isIntersect = (line1, line2)=>{
    // 转换成一般式: Ax+By = C
      //   console.log(305, line1, line2);
      var a1 = line1.y2 - line1.y1;
      var b1 = line1.x1 - line1.x2;
      var c1 = a1 * line1.x1 + b1 * line1.y1;

      //转换成一般式: Ax+By = C
      var a2 = line2.y2 - line2.y1;
      var b2 = line2.x1 - line2.x2;
      var c2 = a2 * line2.x1 + b2 * line2.y1;

      // 计算交点
      var d = a1 * b2 - a2 * b1;
      // 当d==0时，两线平行
      if (d == 0) {
        return false;
      } else {
        var x = (b2 * c1 - b1 * c2) / d;
        var y = (a1 * c2 - a2 * c1) / d;

        // 检测交点是否在两条线段上
        if (
          (isInBetween(line1.x1, x, line1.x2) || isInBetween(line1.y1, y, line1.y2)) &&
          (isInBetween(line2.x1, x, line2.x2) || isInBetween(line2.y1, y, line2.y2))
        ) {
          console.log(331);
          return true;
        }
      }
      console.log(335);

      return false;
}

const isInBetween = (a, b, c) => {
   // 如果b几乎等于a或c，返回false.为了避免浮点运行时两值几乎相等，但存在相差0.00000...0001的这种情况出现使用下面方式进行避免
   if (Math.abs(a - b) < 0.000001 || Math.abs(b - c) < 0.000001) {
        return false;
      }

      return (a < b && b < c) || (c < b && b < a);
}

const canvasMove  =(e)=>{
      //画布中鼠标移动
      //没开始画或者结束画之后不进行操作
      var x = e.offsetX;
      var y = e.offsetY;
      if (isdrag.value) {
        ctx.value.clearRect(0, 0, canvasWidth.value, canvasHeight.value);
        all_coordinates.value[drag_index.value[0]][drag_index.value[1]].cor_x = x;
        all_coordinates.value[drag_index.value[0]][drag_index.value[1]].cor_y = y;
        drawlines();
        drawcircles();
        fillarea();
      }
      //   console.log(338, coordinates.length == 0, !isdraw, endtip);
      if (coordinates.length == 0 || !isdraw.value || endtip.value) {
        return 0;
      }

      //获取上一个点
      var last_x = coordinates[coordinates.length - 1].cor_x;
      var last_y = coordinates[coordinates.length - 1].cor_y;
      ctx.value.clearRect(0, 0, canvasWidth.value, canvasHeight.value); //清空画布
      drawline(); //把之前的点连线
      drawcircle();
      if (all_coordinates.value.length != 0) {
        //不止一个多边形，把多边形们画出来
        drawlines();
        drawcircles();
        fillarea();
      }
      //获取鼠标移动时的点，画线，实现线段跟踪效果。
      ctx.value.beginPath();
      ctx.value.moveTo(last_x, last_y);

      ctx.value.lineTo(x, y);
      ctx.value.stroke();
      ctx.value.closePath();
}


const drawClosePath = () => {
  isdraw.value = false;
      endtip.value = true;
      all_coordinates.value.push(coordinates);

      ctx.value.clearRect(0, 0, canvasWidth.value, canvasHeight.value);
      ctx.value.fillStyle = 'rgba(255, 77, 79,0.1)';
      var bx = coordinates[0].cor_x;
      var by = coordinates[0].cor_y;
      ctx.value.beginPath();
      ctx.value.moveTo(bx, by);
      for (var k = 1; k < coordinates.length; k++) {
        var x = coordinates[k].cor_x;
        var y = coordinates[k].cor_y;
        ctx.value.lineTo(x, y);
      }
      ctx.value.lineTo(bx, by);
      ctx.value.stroke();
      ctx.value.fill();
      if (isShowBox.value) {
        drawcircles();
      }
      ctx.value.closePath();
      coordinates.splice(0, coordinates.length);
}
</script>

<style scoped>
.mains {
  width: 100%;
  height: 100%;
  color: black;
  /* background: white; */
}

.mycanvas {
  border: 1px solid red;
  margin: auto;
  display: block;
  box-sizing: border-box;
}
</style>